package hu.arguscab.ai;

import java.util.LinkedList;
import java.util.List;
import java.util.Queue;

/**
 * A graph whose nodes have only one parent.
 * @author bbodi
 *
 * @param <E>
 * @param <N>
 */
public abstract class AbstractTree<E, N> implements Tree<E, N> {
	
	private Terminator<E, N> terminator;
	private NodeCreator<E, N> creator;
		
	
	/**
	 * @see Graph#evaulate(hu.arguscab.AI.NodeCreator, hu.arguscab.AI.Terminator) 
	 */
	@Override
	public void evaulate() {
		assert terminator != null;
		assert creator != null;
		
		Node<N> root = setRoot(creator.createRoot());
		assert root != null;

		int cost;
		Queue<Node<N>> list = new LinkedList<Node<N>>();
		list.add(root);
		// TODO: CONCURRENCY
		Node<N> node;
		while( (node=list.poll()) != null ) {
			if ( terminator.isTerminate(node) ) {
				continue;
			}
			List<NodePair<E, N>> childs = creator.createNodes(node);
			for ( NodePair<E, N> pair : childs ) {
				// set Edge cost and adding it to the graph
				cost = creator.calcEdgeCost(pair.getEdge());
				// [A] -> [[B] -> [C]]
				// Here, B and C nodes make a pair, and node A is the parent of node B.
				// So I add the cost from A to B to the Edge joint B and C.
				Node<N> parent = getParent( pair.getFrom() );
				if ( parent != null ) {
					cost += getEdge(parent, pair.getFrom()).getWeight();
				}
				pair.getEdge().setWeight( cost );
				
				addNodePair(pair);
				// Open list management
				list.add(pair.getTo());
			}
		}
	}
	
	public void setCreator(NodeCreator<E, N> creator) {
		this.creator = creator;
	}

	public void setTerminator(Terminator<E, N> terminator) {
		this.terminator = terminator;
	}

	public NodeCreator<E, N> getCreator() {
		return creator;
	}

	public Terminator<E, N> getTerminator() {
		return terminator;
	}

	
}
